package com.regent.central.bill.service.bean.mrp;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.regent.central.bill.common.*;
import com.regent.central.bill.core.Remittance;
import com.regent.central.bill.core.mrp.ActionMaterialPurchase;
import com.regent.central.bill.core.mrp.BillMaterialPurchase;
import com.regent.central.bill.core.mrp.BillMaterialPurchaseActions;
import com.regent.central.bill.repository.RemittanceMapper;
import com.regent.central.bill.repository.mrp.BillMaterialArriveMapper;
import com.regent.central.bill.repository.mrp.BillMaterialPurchaseActionsMapper;
import com.regent.central.bill.repository.mrp.BillMaterialPurchaseMapper;
import com.regent.central.bill.repository.mrp.BillMaterialPurchaseSkuMapper;
import com.regent.central.bill.repository.mrp.dto.*;
import com.regent.central.bill.repository.mrp.dto.arrive.PurchaseMaterialRemittanceDTO;
import com.regent.central.bill.repository.page.Pagination;
import com.regent.central.bill.service.bean.mrp.util.MrpOrderNoGenerateUtil;
import com.regent.central.bill.service.mrp.ActionMaterialPurchaseService;
import com.regent.central.bill.service.mrp.BillMaterialArriveService;
import com.regent.central.bill.service.mrp.BillMaterialPurchaseService;
import com.regent.central.bill.service.mrp.BillMaterialPurchaseSkuService;
import com.regent.central.infrastructure.common.Uid;
import com.regent.central.infrastructure.service.bean.DomainServiceBean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
public class BillMaterialPurchaseServiceBean extends DomainServiceBean<BillMaterialPurchaseMapper, BillMaterialPurchase> implements BillMaterialPurchaseService {

    @Resource
    private BillMaterialPurchaseMapper billMaterialPurchaseMapper;

    @Resource
    private BillMaterialPurchaseActionsMapper billMaterialPurchaseActionsMapper;

    @Resource
    private ActionMaterialPurchaseService actionMaterialPurchaseService;

    @Resource
    private RemittanceMapper remittanceMapper;

    @Resource
    private BillMaterialArriveService billMaterialArriveService;

    @Resource
    private BillMaterialPurchaseSkuService billMaterialPurchaseSkuService;

    @Resource
    private BillMaterialPurchaseSkuMapper billMaterialPurchaseSkuMapper;

    @Resource
    private BillMaterialArriveMapper billMaterialArriveMapper;

    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public void create(MaterialPurchaseAddDTO purchaseAddDTO) {
        String orderNo = purchaseAddDTO.getOrderNo();
        if (StringUtils.isEmpty(orderNo)) {
            orderNo = getOrderNumber(purchaseAddDTO.getUnitId());
        }
        BigDecimal amountPay = purchaseAddDTO.getAmountPay();

        BillMaterialPurchase billMaterialPurchase = new BillMaterialPurchase();
        billMaterialPurchase.setId(Uid.random());
        billMaterialPurchase.setAmountPay(amountPay);
        billMaterialPurchase.setCreatorId(purchaseAddDTO.getCreatorId());
        billMaterialPurchase.setCreatorName(purchaseAddDTO.getCreatorName());
        String expectDateEnd = purchaseAddDTO.getExpectDateEnd();
        billMaterialPurchase.setExpectDateEnd(StringUtils.isEmpty(expectDateEnd) ? new Date() : DateUtil.formartToDate(expectDateEnd, "yyy-MM-dd HH:mm:ss", "yyyy-MM-dd"));
        billMaterialPurchase.setOrderNo(orderNo);
        billMaterialPurchase.setRemark(purchaseAddDTO.getRemark());
        billMaterialPurchase.setUnitId(purchaseAddDTO.getUnitId());
        billMaterialPurchase.setBossUnitId(purchaseAddDTO.getBossUnitId());
        billMaterialPurchase.setSupplierId(purchaseAddDTO.getSupplierId());
        String datePurchase = purchaseAddDTO.getDatePurchase();
        billMaterialPurchase.setDatePurchase(StringUtils.isEmpty(datePurchase) ? new Date() : DateUtil.merge(DateUtil.formatToDateDefault(datePurchase), new Date()));
        billMaterialPurchaseMapper.insertSelective(billMaterialPurchase);

        // 如果付了款，要记流水
        if (amountPay != null) {
            Remittance remittance = new Remittance();
            remittance.setId(Uid.random());
            remittance.setAmount(amountPay);
            remittance.setBossUnitId(purchaseAddDTO.getBossUnitId());
            remittance.setUnitId(purchaseAddDTO.getUnitId());
            remittance.setOperatorId(purchaseAddDTO.getCreatorId());
            remittance.setSource(BillType.MATERIAL_PURCHASE);
            remittance.setSupplierId(purchaseAddDTO.getSupplierId());
            remittance.setUserCreated(purchaseAddDTO.getCreatorId());
            remittance.setType(RemittanceType.PAYMENT);
            remittance.setDateOperated(new Date());
            remittanceMapper.insertSelective(remittance);

            // 建立采购单和流水的关系
            BillMaterialPurchaseActions actions = new BillMaterialPurchaseActions();
            actions.setId(Uid.random());
            actions.setActionId(remittance.getId());
            actions.setActionType(ActionType.REMITTANCE.name());
            actions.setCentralBillMaterialPurchaseId(billMaterialPurchase.getId());
            billMaterialPurchaseActionsMapper.insertSelective(actions);
        }

        // 采购动作
        Set<MaterialPurchaseAddDTO.PurchaseAddMaterialsSkuDTO> materialsSkus = purchaseAddDTO.getMaterialsSkus();
        Set<ActionMaterialPurchase> actionMaterialPurchases = new HashSet<>();
        Set<MaterialPurchaseAddDTO.PurchaseAddMaterialsSkuDTO> directArrives = new HashSet<>();
        for (MaterialPurchaseAddDTO.PurchaseAddMaterialsSkuDTO sku : materialsSkus) {
            ActionMaterialPurchase actionMaterialPurchase = new ActionMaterialPurchase();
            actionMaterialPurchase.setId(Uid.random());
            actionMaterialPurchase.setCommonMaterialsSkuId(sku.getMaterialsSkuId());
            actionMaterialPurchase.setFacMissionId(sku.getFacMissionId());
            actionMaterialPurchase.setPriceUnit(sku.getPriceUnit());
            actionMaterialPurchase.setQuantity(sku.getQuantity());
            // 工单ID为空就认为是计划外采购
            Integer type = StringUtils.isEmpty(sku.getFacMissionId()) ? 1 : 0;
            actionMaterialPurchase.setType(type);
            actionMaterialPurchase.setStyleNo(sku.getStyleNo());
            actionMaterialPurchase.setCommonMaterialsId(sku.getMaterialsId());
            actionMaterialPurchase.setCommonMaterialsNo(sku.getMaterialsNo());
            BigDecimal priceTotal = actionMaterialPurchase.getPriceUnit().multiply(actionMaterialPurchase.getQuantity());
            actionMaterialPurchase.setPriceTotal(priceTotal);
            actionMaterialPurchases.add(actionMaterialPurchase);

            boolean directArrive = sku.isDirectArrive();
            if (directArrive) {
                directArrives.add(sku);
            }
        }
        actionMaterialPurchases = actionMaterialPurchaseService.saveActions(actionMaterialPurchases);

        // 建立采购单物料sku二级数据
        billMaterialPurchaseSkuService.saveByActionPurchase(billMaterialPurchase.getId(), actionMaterialPurchases);

        // 维护采购单和采购动作的关系
        for (ActionMaterialPurchase actionPurchase : actionMaterialPurchases) {
            String actionPurchaseId = actionPurchase.getId();

            BillMaterialPurchaseActions actions = new BillMaterialPurchaseActions();
            actions.setId(Uid.random());
            actions.setActionId(actionPurchaseId);
            actions.setActionType(ActionType.MATERIAL_PURCHASE.name());
            actions.setCentralBillMaterialPurchaseId(billMaterialPurchase.getId());
            billMaterialPurchaseActionsMapper.insertSelective(actions);
        }

        if (directArrives.size() > 0) {
            // 如果有直接到料
            BillMaterialArriveAddDTO arriveAddDTO = new BillMaterialArriveAddDTO();
            arriveAddDTO.setCreatorId(purchaseAddDTO.getCreatorId());
            arriveAddDTO.setCreatorName(purchaseAddDTO.getCreatorName());
            arriveAddDTO.setDateArrive(new Date());
            arriveAddDTO.setUnitId(purchaseAddDTO.getUnitId());
            arriveAddDTO.setBossUnitId(purchaseAddDTO.getBossUnitId());
            arriveAddDTO.setStorehouseId(purchaseAddDTO.getArriveStorehouseId());
            arriveAddDTO.setSupplierId(purchaseAddDTO.getSupplierId());
            for (MaterialPurchaseAddDTO.PurchaseAddMaterialsSkuDTO sku : directArrives) {
                BillMaterialArriveAddDTO.ArriveAddMaterialsSkuDTO materialsSkuDTO = new BillMaterialArriveAddDTO.ArriveAddMaterialsSkuDTO();
                materialsSkuDTO.setFacMissionId(sku.getFacMissionId());
                materialsSkuDTO.setBillMaterialPurchaseId(billMaterialPurchase.getId());
                materialsSkuDTO.setMaterialsId(sku.getMaterialsId());
                materialsSkuDTO.setMaterialsNo(sku.getMaterialsNo());
                materialsSkuDTO.setMaterialsSkuId(sku.getMaterialsSkuId());
                materialsSkuDTO.setPriceUnit(sku.getPriceUnit());
                materialsSkuDTO.setQuantity(sku.getQuantity());
                materialsSkuDTO.setStyleNo(sku.getStyleNo());
                materialsSkuDTO.setType(sku.getType());
                arriveAddDTO.getMaterialsSkus().add(materialsSkuDTO);
            }
            billMaterialArriveService.create(arriveAddDTO);
        }

    }

    @Override
    public String getOrderNumber(String unitId) {
        LocalDate now = LocalDate.now();
        String startDate = now.toString() + " 00:00:00";
        String endDate = now.toString() + " 23:59:59";

        LocalDateTime dateStart = LocalDateTime.parse(startDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        LocalDateTime dateEnd = LocalDateTime.parse(endDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        int count = billMaterialPurchaseMapper.countPurchaseByUnitId(unitId, dateStart, dateEnd);
        return MrpOrderNoGenerateUtil.generate(count, "CW");
    }

    @Override
    public BillMaterialPurchasePageDTO listMaterialPurchase(BillMaterialPurchaseQueryDTO billMaterialPurchaseQueryDTO, Integer pageNum, Integer pageSize) {
        pageNum = pageNum == null || pageNum <= 0 ? 1 : pageNum;
        pageSize = pageSize == null || pageSize <= 0 ? 20 : pageSize;

        Page<String> page = PageHelper.startPage(pageNum, pageSize);
        billMaterialPurchaseMapper.listBillMaterialsPurchaseIds(billMaterialPurchaseQueryDTO);

        List<MaterialPurchaseDTO> materialPurchaseDTOS = new ArrayList<>();
        if (page.size() > 0) {
            materialPurchaseDTOS = billMaterialPurchaseMapper.listMaterialPurchaseByBillPurchaseIds(page);
        }

        BillMaterialPurchasePageDTO billMaterialPurchasePageDTO = new BillMaterialPurchasePageDTO();
        Pagination<MaterialPurchaseDTO> pagination = new Pagination<>();
        pagination.setDataList(materialPurchaseDTOS);
        pagination.setPageSize(pageSize);
        pagination.setPageNum(pageNum);
        pagination.setTotal((int) page.getTotal());
        billMaterialPurchasePageDTO.setList(materialPurchaseDTOS);
        billMaterialPurchasePageDTO.setPagination(pagination);
        return billMaterialPurchasePageDTO;
    }

    @Override
    public BillMaterialPurchaseDetailDTO getBillPurchase(String billMaterialPurchaseId) {
        BillMaterialPurchaseDetailDTO purchaseDetail = billMaterialPurchaseMapper.getBillPurchaseBasic(billMaterialPurchaseId);

        if (purchaseDetail == null) {
            return null;
        }

        // 采购信息
        List<MaterialPurchaseDTO> materialPurchases = billMaterialPurchaseMapper.listMaterialPurchase(billMaterialPurchaseId);
        BillMaterialPurchaseDetailDTO.PurchaseDTO purchaseDTO = new BillMaterialPurchaseDetailDTO.PurchaseDTO();
        Set<String> materialsIds = new HashSet<>();
        BigDecimal total = BigDecimal.ZERO;
        for (MaterialPurchaseDTO materialPurchase : materialPurchases) {
            materialsIds.add(materialPurchase.getCommonMaterialsId());
            total = total.add(materialPurchase.getPriceTotal());
        }
        purchaseDTO.setAmountTotal(total);
        purchaseDTO.setQuantityMaterials(materialsIds.size());
        purchaseDTO.setPurchases(materialPurchases);
        purchaseDetail.setPurchase(purchaseDTO);

        // 到料信息
        List<MaterialArriveDTO> materialArrives = billMaterialPurchaseMapper.listMaterialArrive(billMaterialPurchaseId);
        BillMaterialPurchaseDetailDTO.ArriveDTO arriveDTO = new BillMaterialPurchaseDetailDTO.ArriveDTO();
        BigDecimal arriveTotal = BigDecimal.ZERO;
        for (MaterialArriveDTO materialArrive : materialArrives) {
            arriveTotal = arriveTotal.add(materialArrive.getPriceTotal());
        }
        arriveDTO.setAmountTotal(arriveTotal);
        arriveDTO.setArrives(materialArrives);
        purchaseDetail.setArrive(arriveDTO);

        // 流水信息
        List<MaterialRemittanceDetailDTO> materialRemittances = billMaterialPurchaseMapper.listMaterialRemittance(billMaterialPurchaseId);
        BillMaterialPurchaseDetailDTO.MaterialRemittanceDTO remittanceDTO = new BillMaterialPurchaseDetailDTO.MaterialRemittanceDTO();
        BigDecimal remittanceTotal = BigDecimal.ZERO;
        for (MaterialRemittanceDetailDTO materialRemittance : materialRemittances) {
            remittanceTotal = remittanceTotal.add(materialRemittance.getAmount());
        }
        remittanceDTO.setAmountActual(remittanceTotal);
        remittanceDTO.setAmountTarget(arriveTotal);
        remittanceDTO.setRemittances(materialRemittances);
        purchaseDetail.setRemittance(remittanceDTO);

        return purchaseDetail;
    }

    @Override
    @Transactional
    public void keepBillPurchaseArriveStatus(String billMaterialPurchaseId) {
        List<BillMaterialPurchaseArriveInfoDTO> infoDTOS = billMaterialPurchaseMapper.listArriveStatus(billMaterialPurchaseId);
        for (BillMaterialPurchaseArriveInfoDTO infoDTO : infoDTOS) {
            String facMissionId = infoDTO.getFacMissionId();
            String materialsSkuId = infoDTO.getMaterialsSkuId();
            BillPurchaseArriveStatus arriveStatus;

            BigDecimal quantityArrive = infoDTO.getQuantityArrive();
            BigDecimal quantityTarget = infoDTO.getQuantityTarget();
            quantityArrive = quantityArrive == null ? BigDecimal.ZERO : quantityArrive;
            quantityTarget = quantityTarget == null ? BigDecimal.ZERO : quantityTarget;
            if (quantityArrive.compareTo(BigDecimal.ZERO) <= 0) {
                arriveStatus = BillPurchaseArriveStatus.INITIAL;
            } else if (quantityArrive.compareTo(quantityTarget) < 0) {
                arriveStatus = BillPurchaseArriveStatus.PROCESSING;
            } else {
                arriveStatus = BillPurchaseArriveStatus.COMPLETED;
            }

            billMaterialPurchaseSkuService.setArriveStatusSystem(arriveStatus, billMaterialPurchaseId, facMissionId, materialsSkuId);
            billMaterialPurchaseSkuService.setQuantityArrive(quantityArrive, billMaterialPurchaseId, facMissionId, materialsSkuId);
        }

        BillPurchaseArriveStatusQTO billPurchaseArriveStatusQTO = billMaterialPurchaseSkuMapper.getArriveStatusByBillPurchase(billMaterialPurchaseId);
        if (billPurchaseArriveStatusQTO != null) {
            if (billPurchaseArriveStatusQTO.isInitial()) {
                // 未到料
                billMaterialPurchaseMapper.setArriveStatus(billMaterialPurchaseId, BillPurchaseArriveStatus.INITIAL.getValue());
            } else if (billPurchaseArriveStatusQTO.isProcessing()) {
                // 未到齐
                billMaterialPurchaseMapper.setArriveStatus(billMaterialPurchaseId, BillPurchaseArriveStatus.PROCESSING.getValue());
            } else {
                // 已到齐
                billMaterialPurchaseMapper.setArriveStatus(billMaterialPurchaseId, BillPurchaseArriveStatus.COMPLETED.getValue());
            }
        }
    }

    @Override
    public List<String> listOrderNoByUnitId(String unitId) {
        return billMaterialPurchaseMapper.listOrderNoByUnitId(unitId);
    }

    @Transactional
    @Override
    public void remit(PurchaseMaterialRemittanceDTO materialRemittanceDTO) {
        Remittance remittance = new Remittance();
        remittance.setId(Uid.random());
        remittance.setAmount(materialRemittanceDTO.getAmount());
        remittance.setBossUnitId(materialRemittanceDTO.getBossUnitId());
        remittance.setOperatorId(materialRemittanceDTO.getOperatorId());
        remittance.setSource(BillType.MATERIAL_PURCHASE);
        remittance.setSupplierId(materialRemittanceDTO.getSupplierId());
        remittance.setType(RemittanceType.PAYMENT);
        remittance.setUnitId(materialRemittanceDTO.getUnitId());
        remittance.setUserCreated(materialRemittanceDTO.getUserCreated());
        String dateOperated = materialRemittanceDTO.getDateOperated();
        Date dateOperatedDate = dateOperated == null ? new Date() : DateUtil.formartToDate(materialRemittanceDTO.getDateOperated(), "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd");
        remittance.setDateOperated(dateOperatedDate);
        remittanceMapper.insertSelective(remittance);

        String billMaterialPurchaseId = materialRemittanceDTO.getBillMaterialPurchaseId();
        // 建立付款和采购单的关系
        BillMaterialPurchaseActions billMaterialPurchaseActions = new BillMaterialPurchaseActions();
        billMaterialPurchaseActions.setId(Uid.random());
        billMaterialPurchaseActions.setActionType(ActionType.REMITTANCE.name());
        billMaterialPurchaseActions.setCentralBillMaterialPurchaseId(billMaterialPurchaseId);
        billMaterialPurchaseActions.setActionId(remittance.getId());
        billMaterialPurchaseActionsMapper.insertSelective(billMaterialPurchaseActions);
    }

    @Transactional
    @Override
    public PurchaseUndoResult undo(String billMaterialPurchaseId) {
        PurchaseUndoResult result = new PurchaseUndoResult();
        // 先判断采购单是否有到料
        boolean hasArrived = billMaterialArriveMapper.hasBillMaterialArriveByPurchaseId(billMaterialPurchaseId);
        BillMaterialPurchaseDetailDTO purchaseDetailDTO = billMaterialPurchaseMapper.getBillPurchaseBasic(billMaterialPurchaseId);
        if (purchaseDetailDTO == null) {
            // 没有改采购单
            result.setSuccess(false);
            return result;
        }
        if (hasArrived || purchaseDetailDTO.getAmountPay().compareTo(BigDecimal.ZERO) > 0) {
            // 有到料 和 有付款金额 不准撤销
            result.setSuccess(false);
            return result;
        }
        // 伪删除采购单基本信息 timeDelete 设为1 表示撤销 xux
        billMaterialPurchaseMapper.undo(billMaterialPurchaseId, 0);
        billMaterialPurchaseMapper.undoAction(billMaterialPurchaseId);
        //伪删除采购单sku信息 timeDelete 设为1 表示撤销 xux
        billMaterialPurchaseSkuMapper.undo(billMaterialPurchaseId, 0);
        result.setSuccess(true);
        return result;
    }

    @Transactional
    @Override
    public void manualArriveComplete(String billMaterialPurchaseId, String facMissionId, String materialSkuId) {
        billMaterialPurchaseSkuService.setArriveStatus(BillPurchaseArriveStatus.COMPLETED, billMaterialPurchaseId, facMissionId, materialSkuId, DataChangeType.USER_OPERATE);
    }
}